﻿using System;
using System.Linq.Expressions;
using System.Threading.Tasks;

using Tszy.Unlimited.Base.Exceptions;
using Tszy.Unlimited.Data.AdoNet.Sql.Components.Expressions;
using Tszy.Unlimited.Data.AdoNet.Sql.Components.Expressions.Values;
using Tszy.Unlimited.Data.AdoNet.Sql.Components.Expressions.Where;
using Tszy.Unlimited.Data.AdoNet.Sql.Providers;

namespace Tszy.Unlimited.Data.AdoNet.Sql.Components.Db.Mysql
{
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    internal class Editor<TSource> : QueryBase<TSource>, IEditor<TSource>, IPropertyEditor<TSource>, IWhereEditor<TSource>, IExecuteEditor<TSource> where TSource : new()
    {
        private readonly IExecuteEditorFactory _executeEditFactory = null;

        /// <summary>
        ///
        /// </summary>
        protected static readonly IExpressionExecutor _whereExpressionExecutor = new WhereExpressionExecutor();

        #region 构造器

        /// <summary>
        ///
        /// </summary>
        public Editor(IExecuteEditorFactory executeEditFactory) : base()
        {
            _executeEditFactory = executeEditFactory;

            Context.EntityType = typeof(TSource);
        }

        #endregion 构造器

        #region 更新

        #region 重置属性

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="propertyValue"></param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, short>> predicate, short propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="propertyValue"></param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, short?>> predicate, short? propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="propertyValue"></param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, int>> predicate, int propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="propertyValue"></param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, int?>> predicate, int? propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="propertyValue"></param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, long>> predicate, long propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, long?>> predicate, long? propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, float>> predicate, float propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, float?>> predicate, float? propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, double>> predicate, double propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, double?>> predicate, double? propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, decimal>> predicate, decimal propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, decimal?>> predicate, decimal? propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, string>> predicate, string propertyValue)
        {
            propertyValue ??= string.Empty;

            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, bool>> predicate, bool propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, bool?>> predicate, bool? propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetProperty(Expression<Func<TSource, DateTime>> predicate, DateTime propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> SetEnumProperty<TResult>(Expression<Func<TSource, TResult>> predicate, object propertyValue)
        {
            if (!typeof(TResult).IsEnum)
            {
                throw new ArgumentException("TResult must be an enumerated type");
            }

            var value = (int)propertyValue;

            return InnerSetProperty(predicate, value);
        }

        /// <summary>
        /// 设置属性。
        /// </summary>
        /// <remarks>
        /// 使用指定的属性值来替换原有的属性。
        /// </remarks>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns>属性编辑器。</returns>
        public IPropertyEditor<TSource> SetObjectProperty<TResult>(Expression<Func<TSource, TResult>> predicate, object propertyValue)
        {
            return InnerSetProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 使用更新语句来更新自身唯一标识来判断该数据是否是唯一。
        /// </summary>
        /// <returns></returns>
        public IWhereEditor<TSource> SetUniqueProperty()
        {
            var context = Context.Clone();

            context.SetUniqueProperty = true;

            return new Editor<TSource>(_executeEditFactory) { Context = context };
        }

        private IPropertyEditor<TSource> InnerSetProperty(Expression predicate, object propertyValue)
        {
            if (predicate == null)
                throw new ArgumentNullException(nameof(predicate));

            var context = Context.Clone();

            var property = GetPropertyName(predicate);

            var propertyName = $"{property.Value}";

            context.SetProperties[propertyName] = propertyValue ?? throw new ArgumentNullException(nameof(propertyValue));

            return new Editor<TSource>(_executeEditFactory) { Context = context };
        }

        #endregion 重置属性

        #region 累加属性

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, short>> predicate, short propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, short?>> predicate, short? propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, int>> predicate, int propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, int?>> predicate, int? propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, long>> predicate, long propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, long?>> predicate, long? propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, float>> predicate, float propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, float?>> predicate, float? propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, double>> predicate, double propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, double?>> predicate, double? propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, decimal>> predicate, decimal propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, decimal?>> predicate, decimal? propertyValue)
        {
            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        /// <summary>
        /// 累加指定属性的值。
        /// </summary>
        /// <param name="predicate">属性名。</param>
        /// <param name="propertyValue">属性值。</param>
        /// <returns></returns>
        public IPropertyEditor<TSource> AccumulatedProperty(Expression<Func<TSource, string>> predicate, string propertyValue)
        {
            propertyValue ??= string.Empty;

            return InnerAccumulatedProperty(predicate, propertyValue);
        }

        private IPropertyEditor<TSource> InnerAccumulatedProperty(Expression predicate, object propertyValue)
        {
            if (predicate == null)
                throw new ArgumentNullException(nameof(predicate));

            var context = Context.Clone();

            var property = GetPropertyName(predicate);

            var propertyName = $"{property.Value}";

            context.AccumulatedProperties[propertyName] = propertyValue ?? throw new ArgumentNullException(nameof(propertyValue));

            return new Editor<TSource>(_executeEditFactory) { Context = context };
        }

        #endregion 累加属性

        private ValueExpressionResult GetPropertyName(Expression predicate)
        {
            var context = Context.Clone();

            if (predicate.NodeType == ExpressionType.Lambda)
            {
                var lambdaExpression = predicate as LambdaExpression;

                return ValueExpressionHandler.Handler(context, lambdaExpression?.Body);
            }
            else
            {
                throw new MainApplicationException("表达式类型不是 Lambda");
            }
        }

        #endregion 更新

        #region 条件

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public IWhereEditor<TSource> Where(Expression<Func<TSource, bool>> predicate)
        {
            var context = Context.Clone();

            _whereExpressionExecutor.Execute(context, predicate);

            return new Editor<TSource>(_executeEditFactory) { Context = context };
        }

        #endregion 条件

        #region 执行

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public bool Execute()
        {
            return _executeEditFactory.Create(this).Execute();
            //return new ExecuteEditor<TSource>(this).Execute();
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public async Task<bool> ExecuteAsync()
        {
            return await _executeEditFactory.Create(this).ExecuteAsync();
            //return await new ExecuteEditor<TSource>(this).ExecuteAsync();
        }

        #endregion 执行

        #region 转换至属性更新器

        /// <summary>
        /// 转换至属性更新器。
        /// </summary>
        /// <returns></returns>
        public IPropertyEditor<TSource> ToPropertyEditor()
        {
            return this;
        }

        #endregion 转换至属性更新器
    }
}